package com.intouchtv.ari;

import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.TimerTask;

import com.intouchtv.ari.R;

import model.UrlFile;
import uiHelpers.ButtonAdder;
import Controller.GameController;
import android.app.Activity;
import android.app.ProgressDialog;
import android.graphics.Bitmap;
import android.graphics.Rect;
import android.media.MediaPlayer;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.util.Log;
import android.util.TypedValue;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.view.animation.AlphaAnimation;
import android.view.animation.CycleInterpolator;
import android.widget.AbsoluteLayout;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;
import android.widget.AbsoluteLayout.LayoutParams;

@SuppressWarnings("deprecation")
public class NabDemoView extends Activity implements SurfaceHolder.Callback {

	public GameController controller;

	ProgressDialog myProgressDialog = null;

	private boolean isKilling = false;

	/**
	 * Key - element model id Value - the gui element object
	 */
	private HashMap<Integer, View> globalElements = new HashMap<Integer, View>();

	/**
	 * Key - movieId Value Value - list of events elements
	 */
	private HashMap<Integer, List<View>> movieElements = new HashMap<Integer, List<View>>();

	/**
	 * handle to the UI thread
	 */
	private Handler handler;

	private String xmlUrl;
	
	private boolean normalRun = false;//Indicates that the app started noramly, not pasue -> resume

	private final LayoutParams mainVideoLayoutParams = new AbsoluteLayout.LayoutParams(
			470, 260, 0, 0);
	private final LayoutParams bufferedVideoLayoutParams = new AbsoluteLayout.LayoutParams(
			10, 10, 470, 260);
	private final LayoutParams keepallwaysVideoLayoutParams = new AbsoluteLayout.LayoutParams(
			10, 10, 0, 260);
	AbsoluteLayout layout;

	/** Called when the activity is first created. */
	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		normalRun = true;
		setContentView(R.layout.main);
		xmlUrl = this.getIntent().getDataString();
		if (xmlUrl == null || xmlUrl.equals(""))
			//xmlUrl = "http://cs-cinema-workshop.s3.amazonaws.com/Loci/Demo.xml";
			xmlUrl = "http://cs-cinema-workshop.s3.amazonaws.com/ARI/Game470260.xml";
		handler = new Handler();
	}

	@Override
	protected void onRestart() {
		super.onRestart();
	}

	@Override
	protected void onResume() {
		super.onResume();
		if (!normalRun)
			onCreate(null);
	}
	
	@Override
	protected void onStart() {	
		super.onStart();
		
		isKilling = false;

		layout = (AbsoluteLayout) findViewById(R.id.AbsoluteLayout01);

		startProgressBar();

		Thread worker = new Thread() {
			public void run() {
				controller = new GameController(NabDemoView.this, handler);
				final UrlFile url = new UrlFile(xmlUrl);
				try {
					controller.initGame(url);
				} catch (Exception e) {
					RaiseErrorMsg(e.getMessage());
					return;
				}
				handler.post(new Runnable() {
					@Override
					public void run() {
						controller.playGame();
					}
				});
			}
		};
		worker.start();
	}

	public void doWait(Object myMonitorObject) {
		synchronized (myMonitorObject) {
			try {
				myMonitorObject.wait();
			} catch (InterruptedException e) {
			}
		}
	}

	public void doNotify(Object myMonitorObject) {
		synchronized (myMonitorObject) {
			myMonitorObject.notify();
		}
	}

	MediaPlayer startMp;
	SurfaceView movieView;

	public void startProgressBar() {
		// myProgressDialog = ProgressDialog.show(NabDemoView.this,
		// "Please wait...",
		// "This process can take couple of minutes on slow connections",
		// true);
		try {
			Uri path = Uri.parse("android.resource://" + this.getPackageName()
					+ "/" + R.raw.ariopen);
			startMp = new MediaPlayer();
			startMp.setDataSource(this, path);
			startMp.setLooping(true);
			movieView = new SurfaceView(this);
			movieView.getHolder().setType(
					SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
			movieView.getHolder().addCallback(new SurfaceHolder.Callback() {
				@Override
				public void surfaceCreated(SurfaceHolder holder) {
					try {
						startMp.setDisplay(movieView.getHolder());
						startMp.prepare();
						startMp.start();
					} catch (Exception e) {
						Log.d("NabDemo", e.getMessage());
						return;
					}
				}

				@Override
				public void surfaceChanged(SurfaceHolder holder, int format,
						int width, int height) {
				}

				@Override
				public void surfaceDestroyed(SurfaceHolder holder) {
				}
			});
			this.addSurfaceViewAsMainView(movieView);
		} catch (Exception e) {
			Log.d("NabDemo", e.getMessage());
		}
	}

	public void stopProgressBar() {
		startMp.stop();
		startMp.release();
		this.removeView(movieView);
	}

	public Map<Integer, View> getGlobalElements() {
		return globalElements;
	}

	public synchronized void AddButton(final int movieId, final int id,
			final Rect location, final int color, boolean isVisible,
			final String text, final boolean isShowClickEffect,
			int clickEffectColor) {

		handler.post(new ButtonAdder(NabDemoView.this, movieId, id, location,
				color, isVisible, text, isShowClickEffect, clickEffectColor,
				layout));
	}

	public synchronized void AddPictureBox(final int MovieId, final int id,
			final Rect location, final Bitmap image, Boolean isFlickring, 
			boolean hasEvents) {
		this.AddPictureBox(MovieId, id, location, image, -1, isFlickring, hasEvents);
	}

	public synchronized void AddPictureBox(final int movieId, final int id,
			final Rect location, final Bitmap image, final int duration,
			final Boolean isFlickering, final boolean hasEvents) {

		handler.post(new Runnable() {
			@Override
			public void run() {
				ImageView picBox = null;
				try {
				int _w = location.width();
				int _h = location.height();
				int _x = location.left;
				int _y = location.top;
				int _ww = image.getWidth();
				int _hh = image.getHeight();
				picBox = new ImageView(NabDemoView.this);
				picBox.setLayoutParams(new AbsoluteLayout.LayoutParams(location
						.width(), location.height(), location.left,
						location.top));
				picBox.setImageBitmap(image);
				if (isFlickering) {
					/*
					 * AlphaAnimation(float fromAlpha, float toAlpha)
					 * AlphaAnimation alpha = new AlphaAnimation(1, 0);
					 * 
					 * if (duration > 0) { alpha.setDuration(duration); } else {
					 * alpha.setDuration(Long.MAX_VALUE); }
					 * 
					 * alpha.setInterpolator(new CycleInterpolator(100));
					 * 
					 * picBox.startAnimation(alpha);
					 */

				}
					layout.addView(picBox, picBox.getLayoutParams());
				} catch (Exception e) {
					RaiseErrorMsg("faild loading button" + id);
					return;
				}
				layout.bringChildToFront(picBox);

				addViewToDataStructure(movieId, id, picBox);

				if (hasEvents)
					picBox.setOnClickListener(controller.getEventManager());

				layout.postInvalidate();
				layout.bringToFront();
				layout.postInvalidate();
			}
		});
	}

	public synchronized void AddMovableAnimatedGif(final int movieId,
			final int id, final Rect primeryLocation,
			final Rect secounderyLocation, final Bitmap[] frames) {

		handler.post(new Runnable() {
			@Override
			public void run() {

				final MovableAnimateImageView picBox = new MovableAnimateImageView(
						NabDemoView.this, frames, primeryLocation,
						secounderyLocation);
				picBox.setLayoutParams(new AbsoluteLayout.LayoutParams(
						primeryLocation.width(), primeryLocation.height(),
						primeryLocation.left, primeryLocation.top));

				picBox.invalidate();
				try {
					layout.addView(picBox, picBox.getLayoutParams());
				} catch (Exception e) {
					RaiseErrorMsg("faild loading pic " + id);
					return;
				}
				layout.bringChildToFront(picBox);

				addViewToDataStructure(movieId, id, picBox);

				layout.postInvalidate();
			}
		});

	}

	public synchronized void AddAnimatedGif(final int movieId, final int id,
			final Rect location, final Bitmap[] frames) {

		handler.post(new Runnable() {
			@Override
			public void run() {

				final AnimatedImageView picBox = new AnimatedImageView(
						NabDemoView.this, frames);
				picBox.setLayoutParams(new AbsoluteLayout.LayoutParams(location
						.width(), location.height(), location.left,
						location.top));

				picBox.invalidate();
				try {
					layout.addView(picBox, picBox.getLayoutParams());
				} catch (Exception e) {
					RaiseErrorMsg("faild loading pic " + id);
					return;
				}
				layout.bringChildToFront(picBox);

				addViewToDataStructure(movieId, id, picBox);

				layout.postInvalidate();
			}
		});

	}

	public class AnimationTimerTask extends TimerTask {
		int numCurrentFrame = 0;
		ImageView view;
		Bitmap[] frames;

		public AnimationTimerTask(ImageView view, Bitmap[] frames) {
			this.view = view;
			this.frames = frames;
		}

		@Override
		public void run() {
			numCurrentFrame = (numCurrentFrame + 1) % (frames.length);
			view.setImageBitmap(frames[numCurrentFrame]);
			view.postInvalidate();
		}
	}

	public synchronized void AddMovablePictureBox(final int movieId,
			final int id, final Rect primeryLocation,
			final Rect secounderyLocation, final Bitmap image) {
		handler.post(new Runnable() {
			@Override
			public void run() {
				MoveablePicture picBox = new MoveablePicture(NabDemoView.this,
						primeryLocation, secounderyLocation);
				picBox.setLayoutParams(new AbsoluteLayout.LayoutParams(
						primeryLocation.width(), primeryLocation.height(),
						primeryLocation.left, primeryLocation.top));

				picBox.setImageBitmap(image);
				picBox.invalidate();
				try {
					layout.addView(picBox, picBox.getLayoutParams());
				} catch (Exception e) {
					RaiseErrorMsg("faild loading pic " + id);
					return;
				}
				layout.bringChildToFront(picBox);

				addViewToDataStructure(movieId, id, picBox);

				layout.postInvalidate();
			}
		});
	}

	public synchronized void AddTextBox(final int movieId, final int id,
			final Rect location, final int color, final String text,
			final boolean isFlickering) {

		handler.post(new Runnable() {
			@Override
			public void run() {
				TextView textBox = new TextView(NabDemoView.this);
				textBox.setBackgroundColor(color);
				textBox.setClickable(false);
				textBox.setText(text);
				int width = location.width();
				if (width < textBox.getText().length() * 9)
					width = textBox.getText().length() * 9;

				textBox.setLayoutParams(new AbsoluteLayout.LayoutParams(width,
						location.height(), location.left, location.top));
				textBox.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 13);
				if (isFlickering) {
					// AlphaAnimation(float fromAlpha, float toAlpha)
					AlphaAnimation alpha = new AlphaAnimation(1, 0);

					alpha.setDuration(1000);

					alpha.setInterpolator(new CycleInterpolator(3));

					textBox.startAnimation(alpha);
				}

				try {
					layout.addView(textBox, textBox.getLayoutParams());
				} catch (Exception e) {
					RaiseErrorMsg("faild loading button" + id);
					return;
				}

				layout.bringChildToFront(textBox);

				textBox.setOnClickListener(controller.getEventManager());

				addViewToDataStructure(movieId, id, textBox);

				layout.postInvalidate();
				layout.bringToFront();
			}
		});
	}

	public synchronized void addViewToDataStructure(int movieId, int id,
			View view) {
		// if movieId is 0 then the elements is a global element
		if (movieId == 0) {
			globalElements.put(id, view);
		} else {
			if (movieElements.containsKey(movieId))
				movieElements.get(movieId).add(view);
			else {
				List<View> ls = new LinkedList<View>();
				ls.add(view);
				movieElements.put(movieId, ls);
			}
		}
		view.setId(id);
	}

	@Override
	public void surfaceChanged(SurfaceHolder holder, int format, int width,
			int height) {
	}

	@Override
	public void surfaceCreated(SurfaceHolder holder) {
	}

	@Override
	public void surfaceDestroyed(SurfaceHolder holder) {
	}

	public void RefreshGlobalElements() {
		for (View element : this.globalElements.values()) {
			layout.bringChildToFront(element);
		}
		for (List<View> list : this.movieElements.values()) {
			for (View view : list) {
				layout.bringChildToFront(view);
			}
		}
	}

	public void switchVideoViews(SurfaceView oldView, SurfaceView newView) {
		oldView.setLayoutParams(bufferedVideoLayoutParams);
		newView.setLayoutParams(mainVideoLayoutParams);
		layout.postInvalidate();
	}

	public void addSurfaceViewAsMainView(SurfaceView mainView) {
		mainView.setKeepScreenOn(true);
		layout.addView(mainView, mainVideoLayoutParams);
		layout.postInvalidate();
	}

	public void addSurfaceViewAsBufferingView(SurfaceView buffView) {
		layout.addView(buffView, bufferedVideoLayoutParams);
		layout.postInvalidate();
	}

	public void removeView(SurfaceView oldView) {
		layout.removeView(oldView);
		oldView.destroyDrawingCache();
		oldView.setVisibility(View.INVISIBLE);
		layout.postInvalidate();
	}

	public void makeViewMainView(SurfaceView mainView) {
		mainView.setLayoutParams(mainVideoLayoutParams);
		layout.postInvalidate();
	}

	public void moveViewToAllwaysKeepLocation(SurfaceView mainView) {
		mainView.setLayoutParams(keepallwaysVideoLayoutParams);
		layout.postInvalidate();
	}

	private View getElement(int eventId, int movieId) {

		if (globalElements.containsKey(eventId))
			return globalElements.get(eventId);
		else {
			try {
				for (View element : this.movieElements.get(movieId)) {
					if (element.getId() == eventId)
						return element;
				}
			} catch (Exception e) {
				// RaiseErrorMsg(e.getMessage());
			}
		}
		return null;
	}

	public void removeElement(int eventId, int movieId) {
		final View elementToRemove = getElement(eventId, movieId);

		if (elementToRemove != null) {
			handler.post(new Runnable() {
				@Override
				public void run() {
					View tmp_v = layout.findViewById(elementToRemove.getId());
					layout.removeView(tmp_v);
					layout.postInvalidate();
				}
			});
		}
	}

	public void removeMovieElements(final int id) {
		handler.post(new Runnable() {
			public void run() {
				// check if there are elements is so then remove them
				if (movieElements.get(id) != null) {
					for (View element : movieElements.get(id)) {
						layout.removeView(element);
					}
					layout.postInvalidate();
				}
			}
		});
	}

	/**
	 * 
	 * @param movieId
	 *            - if movieId == 0 then its a global element
	 * @param id
	 *            - if this a global element then its the element id otherwise
	 *            its the eventId
	 */
	public void changeElementText(int movieId, final int id, final String text) {
		if (movieId > 0) {
			// TODO: later if at all needed
		} else {
			handler.post(new Runnable() {
				@Override
				public void run() {
					try {
						// (GameView.this).removeElement(id, 0);
						// globalElements.remove(id);
						// (GameView.this).AddTextBox(0, id,
						// controller.getGlobaleElementLoction(id),
						// controller.getGlobaleElementColor(id), text, false);

						String newText = text;
						if (text.startsWith("@@@")) {
							String curText = ((TextView) globalElements.get(id))
									.getText().toString();
							int curValue = Integer.parseInt(curText);
							Character func = text.charAt(3);
							int arg = Integer.parseInt(text.substring(4, text
									.length()));

							if (func.compareTo('+') == 0) {
								newText = String.valueOf(curValue + arg);
							} else if (func.compareTo('-') == 0) {
								newText = String.valueOf(curValue - arg);
							} else if (func.compareTo('*') == 0) {
								newText = String.valueOf(curValue * arg);
							}

						}

						((TextView) globalElements.get(id)).setText(newText);
						((TextView) globalElements.get(id)).invalidate();
						layout.postInvalidate();
					} catch (Exception e) {
						(NabDemoView.this)
								.RaiseErrorMsg("change text didnt work");
					}
				}
			});
		}
	}

	// Termination Functions:
	private synchronized void release() {
		if (!isKilling) {
			isKilling = true;
			try {
				controller.release();
			} catch (Exception e) {
			}
		}
	}

	public void RaiseErrorMsg(String msg) {
		if (isKilling)
			return;
		isKilling = true;
		final String toastMsg = String.format("ERROR\n%s\n%s\n%s", 
			"Check your Internet connection.",
			"Make sure your phone has WiFi or 3G connection.",
		(msg != null && !msg.equals(""))? "\nDetails:\n"+msg : "");
		handler.post(new Runnable() {
			public void run() {
				try{
				
				Toast t = Toast.makeText(NabDemoView.this, toastMsg, Toast.LENGTH_LONG);
				t.show();
				}
				catch(Exception e)
				{
					Log.d("NabDemo",e.getMessage());
				}
			}
		});
		try {
			Thread.sleep(5000);
		} catch (InterruptedException e) {
		}
		if (startMp != null && startMp.isPlaying())
			startMp.stop();
		finish();
	}

	@Override
	public void onDestroy() {
		release();
		super.onDestroy();
	}

	@Override
	public void onLowMemory() {
		// release();
		Log.w("MiKiZaZa", "MiKiZaZa got Low on memory... nothing to do...");
		super.onLowMemory();
	}

	@Override
	protected void onPause() {
		release();
		super.onPause();
	}

	@Override
	protected void onStop() {
		release();
		super.onStop();
	}

	@Override
	protected void onUserLeaveHint() {
		release();
		super.onUserLeaveHint();
	}

}
